<?php
/**
 * @author Aimon
 * @return Rapid Application Framework
 */
class BaseController extends Controller {

	// CRUD Mode
	public $crud = true;
	
	// Table - Required
	public $table;

	// Table Columns
	public $columns;	

	// Model - Required
	public $model;

	// Variables to be rendered on views
	public $data = [];

	// Validation Rules
	public $rules = [];

	// Error Container
	public $error = [];

	// Layout
	public $layout = 'default';

	// Base
	public $base = '';

	// Views
	public $list = 'list';
	public $index = 'index';
	public $create = 'create';
	public $show = 'show';
	public $edit = 'edit';
	
	// Pagination Limit
	public $limit = 5;

	// Localization
	public $local = 'en';

	// Language
	public $language = 'default';
 
	// Breadcrumbs
	public $breadcrumbs = [];

	// Check if Super User
	public $super_user;
	
	public function __construct() {
		
		// Validation
		/*if( empty($this->table) || empty($this->model) ) {
			exit('Please define Table and Model name in your controller');			
		}*/
		
		// Create View if not exists
		$base = $this->base ? $this->base : $this->table;

		// Set Base Route
		$this->data['base'] = $base;

		// Get Table Columns
		$this->columns = Schema::getColumnListing($this->table);

		
		// If CRUD Mode
		if($this->crud) {

			// Generate Model
			Crud::genearateModel($this->table, $this->model);
			
			// Initialize Generated Class Model
			$this->model = new $this->model;

			// Index
			$this->index = Crud::generateView($this->layout, $base, 'index');

			// List
			$this->list = Crud::generateView($this->layout, $base, 'list');

			// Generate DML Views is CRUD mode is enabled
			$this->create = Crud::generateView($this->layout, $base, 'create');
			$this->edit = Crud::generateView($this->layout, $base, 'edit');
			$this->show = Crud::generateView($this->layout, $base, 'show');
		}

		// Generate Language
		Crud::generateLanguage($this->local, $this->language); 

		// Set Other Languages
		foreach(Lang::get($this->language) as $key=>$lang)
			View::share($key, Lang::get($this->language . '.' . $key));

		// Share Global Vars on Views
		View::share('breadcrumbs', $this->breadcrumbs);	

		if( Auth::check() ) {
			View::share('modules', Permission::getAll(Auth::user()->USER_GROUP_id));

			$this->super_user = Auth::user()->username == Constant::SUPER_USER;

			View::share('super_user', $this->super_user);
		}

	}

	/**
	 * Display the default view of a Module
	 * @author - Aimon
	 * @return Response
	 */
	public function index() {
		if( Permission::check($this->base, Constant::CRUD_READ) || $this->super_user ) {
					
			if( $this->table && $this->model ) {
	
				// Render List View
				$this->renderList();
	
				// Show List only if Ajax
				$index = Request::ajax() ? $this->list : $this->index;
	
				return View::make($index)->with($this->data);
			}
	
			return View::make('home')->with($this->data);
		}
		
		return Redirect::to('/');
	}

	/**
	 * Show the form for creating a new resource.
	 * Form View
	 * @return Response
	 */
	public function create() {
		if(Permission::check($this->base, Constant::CRUD_CREATE) || $this->super_user) {
			$this->setFormData();
			return View::make($this->create)->with($this->data);
		}
		
		return sprintf( Lang::get($this->local . '.' . 'permission_create'), Lang::get($this->language . '.title') );
	}

	/**
	 * Manage Data Before Inserting
 	 * @param $data
	 * @return mixed
	 */
	public function preStore( $data ) {
		return $data;
	}

	/**
	 * Manage Data After Inserting
	 * @param $data, $object
	 * @return mixed
	 */
	public function postStore( $data, $object ) {
		return $data;
	}

	/**
	 * Store a newly created resource in storage.
	 * @return Response
	 */
	public function store() {
		$data = $this->preStore( Input::all() );

		$this->validate( $data );

		if (!count($this->error) ) {
			
			$object = $this->model;

			foreach( array_keys($data) as $key )
				if( !is_array($data[$key]) && in_array($key, $this->columns) )
					$object->{$key} = $data[$key];


			if(Auth::check()) { 
				$object->added_by = Auth::id();
				$object->modified_by = Auth::id();
			}

			$object->save();
			
			$this->postStore( $data, $object );
			Session::flash('message', ucfirst($this->base) . ' Successfully Created!');
		}

		$return['error'] = $this->error;
		
		if( !empty($object->id) )	
			$return['show'] = URL::to($this->base . '/' . $object->id);

		return Request::ajax() ? json_encode($return) : Redirect::to(URL::previous());
	}

	/**
	 * Display the specified resource.
	 * @param  $id
	 * @return Response
	 */
	public function show( $id ) {
		if( Permission::check($this->base, Constant::CRUD_READ) || $this->super_user ) {
			$this->setShowData( $id );
			return View::make( $this->show )->with( $this->data );
		}
		
		return sprintf( Lang::get($this->local . '.' . 'permission_read'), Lang::get($this->language . '.title') );		
	}

	/**
	 * Show the form for editing the specified resource.
	 * @param  $id
	 * @return Response
	 */
	public function edit( $id ) {
		if( Permission::check($this->base, Constant::CRUD_UPDATE) || $this->super_user ) {
			$this->setFormData( $id );	
			return View::make( $this->edit )->with( $this->data );	
		}
				
		return sprintf( Lang::get($this->local . '.' . 'permission_update'), Lang::get($this->language . '.title') );		
		

	}

	
	/**
	 * Update the specified resource in storage.
	 * @param  $id
	 * @return Response
	 */
	public function update( $id ) {
		$data = Input::all();
		$data['id'] = $id;

		$data = $this->preUpdate( $data );
		$this->validate( $data );

		if( !count($this->error) ) {
			$object = $this->model->find( $id );
			 
			foreach( array_keys($data) as $key )
				if( !is_array($data[$key]) && in_array($key, $this->columns) && $key != 'id' )
					$object->{$key} = $data[$key];

			if(Auth::check()) {
				$object->modified_by = Auth::id();
			}

			$object->save();

			$this->postUpdate( $data, $object );
			Session::flash('message', ucfirst($this->base) . ' has been successfuly modified!');
		}

		$return['error'] = $this->error;
		
		if(!empty($object->id))
			$return['show'] = URL::to($this->base . '/' . $object->id);

		return Request::ajax() ? json_encode($return) : Redirect::to(URL::previous());
	}
	
	/**
	 * Manage Data Before Editing
	 * @param  $data
	 * @return Response
	 */
	public function preUpdate( $data ) {
		return $data;
	}
	
	/**
	 * Manage Data After Editing
	 * @param  $data, $object
	 * @return Response
	 */
	public function postUpdate( $data, $object ) {
		return $data;
	}
	
	
	/**
	* Action Before Deletion of Data
	* @param $object
	* @return $object
	*/
	public function preDestroy( $object ) {
		return $object;
	}

	/**
	* Action After Deletion of Data
	* @param $id
	* @return $data
	*/
	public function postDestroy( $id ) {
		return $this->model->where('id', '=', $id)->first();
	}

	/**
	 * Remove the specified resource from storage.
	 *
	 * @param  $id
	 * @return Response
	 */
	public function destroy( $id ) {
		$object = $this->model->find( $id );
		$object = $this->preDestroy( $object );
		$object->modified_by = Auth::id();
		$object->archived = 1;
		$object->save();
		$object->delete();
		Session::flash('message', ucfirst($this->table) . ' has been successfuly removed');
		return $object;
	}

	/**
	 * Set Data List - Set the default list Data
	 *  - Use to override the value of list
	 * @return Null
	 * */
	public function renderList() {
		Session::put('index-' . $this->table, $this->table);

		$this->model = $this->setListData( Input::all(), $this->model );
		$this->data['results'] = $this->model->where( $this->table.'.archived', '=', 0 )->paginate( $this->limit );
		//Backtrack::lastQuery();
		$this->data = $this->addListData( $this->data );
	}

	/**
	 * Set List Filters
	 *  - Use to create filter and Manipulate Model
	 * @return Null
	 * */
	public function setListData( $data, $object ) {
		return $object;
	}

	/**
	* Add List Data - Additional Data on List
	* @param $data
	* @return response
	*/
	public function addListData( $data ) {
		return $data;
	}	
	
	/**
	 * Set Data Form - Set the Default value of form
	 *  - Use to override the value of form
	 * @param $id
	 * @return N/A
	 * */
	public function setFormData( $id=null ) {
		$this->data['result'] = $this->model->where( $this->table . '.archived', '=', 0 )->where($this->table . '.id', '=', $id)->first();
		$this->data = $this->addFormData( $this->data, $id );
	}

	/**
	* Add Form Data - Addional Data on Form
	* @param $data, $id
	* @return $data
	*/
	public function addFormData( $data, $id=null ) {
		return $data;
	}

	/**
	 * Set Show
	 *  - Use to override the value of show data
	 * @param $id
	 * @return N/A	 
	 * */	
	public function setShowData( $id ) {
		$data = $this->model->where( $this->table . '.archived', '=', 0 )->where($this->table . '.id', '=', $id)->first();
		$data = $this->addShowData( $data, $id );
		$this->data['result'] = $data;
	}

	/**
	* Add Show Data - Addional Data on Show
	* @param $data
	* @return response
	*/
	public function addShowData( $data, $id=null ) {
		return $data;
	}	

	/**
	* Data Validator
	* @param $data	 
	* @return N/A
	* */
	public function validate( $data ) {
		$validator = Validator::make($data, $this->rules);
		$messages = $validator->messages();
		foreach($this->rules as $field=>$rule) {
			$errors = $messages->get($field);
			if(!empty($this->error[$field])) {
				$errors = array_merge($errors, $this->error[$field]);
				if($errors)
					$this->error[$field] = $errors;

			} else {
				if($errors)
					$this->error[$field] = $errors;
			}
		}
	}
}